package com.bcw.springtest.config;

import com.bcw.springtest.json.JsonData;
import com.bcw.springtest.json.JsonObject;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

import java.io.IOException;
import java.util.List;

/**
 * controller返回值统一封装
 */
public class BcwResponseBodyWrapper extends RequestResponseBodyMethodProcessor {

    private BeanFactory beanFactory;

    public BcwResponseBodyWrapper(
            List<HttpMessageConverter<?>> messageConverters,
            ContentNegotiationManager contentNegotiationManager, BeanFactory beanFactory) {
        super(messageConverters, contentNegotiationManager);
        if (beanFactory == null) {
            throw new IllegalArgumentException("must init with a beanFactory");
        }
        this.beanFactory = beanFactory;
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
                                  ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

        mavContainer.setRequestHandled(true);

        Object result = buildReturnValue(returnValue);

        writeWithMessageConverters(result, returnType, webRequest);

    }

    private Object buildReturnValue(Object returnValue) {
        if (returnValue == null) {
            return new JsonData();
        }

        if (isWrapped(returnValue)) {
            return returnValue;
        } else {
            return new JsonData(returnValue);
        }
    }

    private boolean isWrapped(Object returnValue) {
        return (returnValue instanceof JsonObject) || isJsonObject(returnValue);
    }

    private boolean isJsonObject(Object returnValue) {
        Class<?> clz = returnValue.getClass();
        while (clz != null) {
            if (clz == JsonObject.class) {
                return true;
            }
            clz = clz.getSuperclass();
        }
        return false;
    }

}
